﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Statistics
{
    /// <summary>
    /// This class provides the computation of the first order partial Pearson correlation coefficient.
    /// </summary>
    [Serializable]
    public class PartialPearsonCorrelation
    {
        /// <summary>
        /// The x vector for the correlation check.
        /// </summary>
        private GeneralVector x;

        /// <summary>
        /// The y vector for the correlation check.
        /// </summary>
        private GeneralVector y;

        /// <summary>
        /// The z vector for the correlation check.
        /// </summary>
        private GeneralVector z;

        /// <summary>
        /// Initializes a new instance of the <see cref="PartialPearsonCorrelation"/> class.
        /// </summary>
        /// <param name="x">The x vector for the correlation check</param>
        /// <param name="y">The y vector for the correlation check</param>
        /// <param name="z">The z vector for the correlation check</param>
        public PartialPearsonCorrelation(GeneralVector x, GeneralVector y, GeneralVector z)
        {
            if (x == (GeneralVector) null)
            {
                throw new ArgumentNullException("x");
            }

            if (y == (GeneralVector) null)
            {
                throw new ArgumentNullException("y");
            }

            if (z == (GeneralVector) null)
            {
                throw new ArgumentNullException("z");
            }

            this.x = x;
            this.y = y;
            this.z = z;
        }

        /// <summary>
        /// Gets or sets the x vector for the correlation check.
        /// </summary>
        /// <value>The x vector for the correlation check.</value>
        public GeneralVector X
        {
            get { return this.x; }
            set { this.x = value; }
        }

        /// <summary>
        /// Gets or sets the y vector for the correlation check.
        /// </summary>
        /// <value>The y vector for the correlation check.</value>
        public GeneralVector Y
        {
            get { return this.y; }
            set { this.y = value; }
        }

        /// <summary>
        /// Gets or sets the z vector for the correlation check.
        /// </summary>
        /// <value>The z vector for the correlation check.</value>
        public GeneralVector Z
        {
            get { return this.z; }
            set { this.z = value; }
        }

        /// <summary>
        /// Computes the partial correlation coefficient.
        /// </summary>
        /// <returns>The partial correlation coefficient.</returns>
        public double ComputeCorrelationCoefficient()
        {
            if ((this.x.Count != this.y.Count) || (this.x.Count != this.z.Count) || (this.y.Count != this.z.Count))
            {
                throw new ArgumentException("The number of components of x, y and z have to be even.");
            }

            PearsonCorrelation rxyEngine = new PearsonCorrelation(this.x, this.y);
            PearsonCorrelation rxzEngine = new PearsonCorrelation(this.x, this.z);
            PearsonCorrelation ryzEngine = new PearsonCorrelation(this.y, this.z);

            double rxy = rxyEngine.ComputeCorrelationCoefficient();
            double rxz = rxzEngine.ComputeCorrelationCoefficient();
            double ryz = ryzEngine.ComputeCorrelationCoefficient();

            return (rxy - rxz*ryz)/(Math.Sqrt(1 - Math.Pow(rxz, 2)*Math.Sqrt(1 - Math.Pow(ryz, 2))));
        }
    }
}